package com.sky.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Category;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.mapper.DishFlavorMapper;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealDishMapper;
import com.sky.result.PageResult;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class DishServiceImpl implements DishService {

    @Autowired
    private DishMapper dishMapper;

    @Autowired
    private DishFlavorMapper dishFlavorMapper;

    @Autowired
    private SetmealDishMapper setmealDishMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 新增菜品
     * @param dish
     */
    @Override
    @Transactional//这里我们要使用事务
    public void addDish(DishDTO dish){
        Dish dishEntity = new Dish();
        //这里我们为了交互要用实体类
        BeanUtils.copyProperties(dish,dishEntity);
        //添加菜品(这里我们使用了我们自己定义的注解来给我们的菜品填充上公共字段(口味要加到口味表里面) 其他的我们使用SQL语句来填充)
        dishMapper.addDish(dishEntity);
        //添加菜品的口味
        //这里我们先获取口味的参数
        List<DishFlavor> flavors = dish.getFlavors();
        //判断确实有元素
        if(flavors!=null&&flavors.size()>0){
            flavors.forEach(flavor->{
                //这里我们因为前端没有给id 所以当我们插入菜品之后要给id
                flavor.setDishId(dishEntity.getId());
            });
            dishFlavorMapper.insertDishFlavor(flavors);
        }
    }

    /**
     * 菜品分页查询
     * @param pagedto
     * @return
     */
    @Override
    @ApiOperation("菜品分页查询")
    public PageResult pagesearch(DishPageQueryDTO pagedto) {
        //DTO进了业务层就需要 看接口文档 利用实体类来处理 (这里我们可以->实体类 然后给pagehelper设置属性 然后再通过动态SQL获得全部的字段)
        //DTO中有我们插件需要的页面和每页展示的个数
        PageHelper.startPage(pagedto.getPage(),pagedto.getPageSize());
        //这里我们要传入这个参数是要它能够动态SQL 查询name/category等
        Page<DishVO> page=dishMapper.page(pagedto);
        return new PageResult(page.getTotal(),page.getResult());
    }

    /**
     * 批量删除菜品
     * 根据业务要求和接口文档
     * @param ids
     */
    @Override
    @ApiOperation("批量删除菜品")
    //加上事务防止有的没被删除
    @Transactional
    public void delete(List<Long> ids) {
        //分析什么功能是需要我们的数据库
        //判断当前菜品是否能够被删除——是否存在起售中的菜品(遍历然后再判断)
        //如果存在一个id是启售的就全部停止 并且抛出异常(使用自定义异常类/自定义常量相关)
        for (Long id : ids) {
            Dish searchbyid = dishMapper.searchbyid(id);
            if (searchbyid.getStatus() == 0) {
                throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
            }
        }
        //判断当前菜品是否能够被删除——是否被套餐关联了
        List<Long> bySetmealId = setmealDishMapper.getSetmealDishIdsBySetmealId(ids);
        if (bySetmealId != null && bySetmealId.size() > 0) {
            throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_SETMEAL);
        }
        //如果可以删除我们就删除对应数据(菜品数据/菜品关联的口味数据)
        for (Long id : ids) {
            dishMapper.deleteid(id);
            dishFlavorMapper.deletebyid(id);
        }
        //删除口味
    }

    /**
     * 根据id查询菜品
     * 多了实体没有的东西所以我们使用vo对象(我们要查询两张表我们要使用外连接)
     * @param id
     * @return
     */
    @Override
    public DishVO dishbyid(Long id) {
        //这里我们通过已经有的方法将操作分成两个
        //根据id查询菜品数据
        Dish dish = dishMapper.searchbyid(id);
        //根据id查询口味数据
        List<DishFlavor> dishFlavor=dishFlavorMapper.searchbyid(id);
        DishVO dishVO=new DishVO();
        //这里我们设置vo数据
        BeanUtils.copyProperties(dish,dishVO);
        dishVO.setFlavors(dishFlavor);
        return dishVO;
    }

    /**
     * 修改菜品
     * 之前我们的查询也可以使用多表查询来解决 但是我们这次最好使用分开处理
     * @param dish
     */
    @Override
    public void update(DishDTO dish) {
        Dish dishEntity = new Dish();
        //这里我们将我们接收的dto来给dish对象然后再更新我们的基本数据
        BeanUtils.copyProperties(dish,dishEntity);
        //修改菜品基本数据
        dishMapper.update(dishEntity);
        //修改菜品口味数据
        List<DishFlavor> flavors = dish.getFlavors();
        //这里是口味处理比较麻烦所以我们就直接删除对应的单条口味然后添加我们请求参数的口味
        dishFlavorMapper.deletebyid(dishEntity.getId());
        //这里设置我们的菜品id
        for(DishFlavor df:flavors){
            df.setDishId(dishEntity.getId());
        }
        dishFlavorMapper.insertDishFlavor(flavors);
    }

    /**
     * 根据分类id来查询菜品(用户端)
     * @param id
     * @return
     */
    @Override
    public List<Dish> typesearch(Long id) {
        //这里注意我们的业务是因为要起售的菜品才能进行查询返回(mapper需要的是Dish对象(需要我们请求参数中的id构造))
        Dish dish = Dish.builder()
                .categoryId(id)
                .status(StatusConstant.ENABLE)
                .build();
        List<Dish> dishlist=dishMapper.typesearch(dish);
        return dishlist;
    }

    /**
     * 用户端 修改菜品状态
     * @param status
     * @param id
     */
    @Override
    public void updateStatus(Integer status, Long id) {
        dishMapper.updatestatus(status,id);
    }


    /**
     * 条件查询菜品和口味
     * 这里我们要根据我们的缓存进行更改(判断我们的缓存是否存在)
     * @param dish
     * @return
     */
    @Override
    public List<DishVO> listWithFlavor(Dish dish) {

        //根据我们的dish实现条件查询
        List<Dish> dishList = dishMapper.typesearch(dish);

        List<DishVO> dishVOList = new ArrayList<>();

        for (Dish d : dishList) {
            DishVO dishVO = new DishVO();
            BeanUtils.copyProperties(d,dishVO);

            //根据菜品id查询对应的口味
            List<DishFlavor> flavors = dishFlavorMapper.searchbyid(d.getId());

            dishVO.setFlavors(flavors);
            dishVOList.add(dishVO);
        }

        return dishVOList;
    }


}
